/**
 * Sonar iOS Client Application
 * Extension for Sonar, open source software quality management tool.
 * Copyright (C) 2011 Maris Plots
 * mailto: maris.plots@gmail.com
 *
 * Sonar iOS Client Application is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * Sonar iOS Client Application is distributed in the hope that it will be 
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Sonar iOS Client Application; if not, write to the Free 
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */

#import "AbstractRESTServiceHandlerSubclass.h"
#import "AbstractRESTServiceHandler.h"
#import "NSString+SonarAdditions.h"
#import "PreferencesManager.h"
#import "NSString+Base64.h"


NSString *const kAbstractRESTServiceHandlerResponseFormatXML = @"xml";
NSString *const kAbstractRESTServiceHandlerResponseFormatJSON = @"json";

@interface AbstractRESTServiceHandler()<NSXMLParserDelegate>
@property (nonatomic, retain, readwrite) id responseDataObject;

- (NSString *)sonar_getSetterTagStackString;
- (NSString *)sonar_getGetterTagStackString;
- (NSString *)sonar_getTagStackStringWithPrefix:(NSString *)prefix 
                                     andSufix:(NSString *)sufix;

- (void)sonar_addParserTagStackString:(NSString *)string;
- (void)sonar_removeParserTagStackString:(NSString *)string;
- (BOOL)sonar_validAbstractParserTagStackString:(NSString *)string;

@end

@implementation AbstractRESTServiceHandler
@synthesize delegate = delegate_;
@synthesize responseDataObject = responseDataObject_;

static NSMutableSet *runningHandlers_ = nil;

#pragma mark -
#pragma mark Memory Management
#pragma mark -
- (void)dealloc{
    if (parsingQueue_!=NULL) {
        dispatch_release(parsingQueue_); parsingQueue_ = NULL;
    }
    [stringBuffer_ release]; stringBuffer_ = nil;
    [receivedData_ release]; receivedData_ = nil;
    [responseDataObject_ release]; responseDataObject_ = nil;
    [super dealloc];
}

#pragma mark -
#pragma mark Interface methods
#pragma mark -
+ (void)executeServiceWithDelegate:(id <AbstractRESTServiceHandlerDelegate>)del{
    AbstractRESTServiceHandler *handler = nil;
    handler = [[[self class] alloc] init];
    handler.delegate = del;
    [handler execute];
    [handler release]; handler = nil;
}

- (id)init{
    self = [super init];
    if(self){
        if(!runningHandlers_){
            runningHandlers_ = [[NSMutableSet alloc] init];
        }
        const char *name = "com.googlecode.sonar.ios.parsing";
        parsingQueue_ = dispatch_queue_create(name, NULL);
    }
    return self;
}

- (void)execute{
    NSString *host = [PreferencesManager getHostName];
    NSString *comp = [self sonar_urlPathComponents];
    NSString *format = [self sonar_responseFormat];
    NSString *strUrl = nil;
    strUrl = [NSString stringWithFormat:@"%@%@?format=%@",host,comp,format];
    NSLog(@"%@",strUrl);
    
    NSURL *url = [NSURL URLWithString:strUrl];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    NSString *credentials = @"admin:admin";
    
    credentials = [credentials sonar_encodeBase64];

    [request addValue:credentials forHTTPHeaderField:@"Authorization: Basic"];
    
    NSURLConnection *conntection = nil;
    receivedData_ = [[NSMutableData alloc] init];
    
    conntection = [NSURLConnection connectionWithRequest:request
                                                delegate:self];

    UIApplication *sharedApplication = [UIApplication sharedApplication];
    sharedApplication.networkActivityIndicatorVisible = YES;
}

#pragma mark -
#pragma mark Abstract Protected methods
#pragma mark -
- (NSString *)sonar_urlPathComponents{
    [self doesNotRecognizeSelector:_cmd];
    return nil;
}

- (NSString *)sonar_responseFormat{
    [self doesNotRecognizeSelector:_cmd];
    return nil;
}

- (BOOL)sonar_validParserTagStackString:(NSString *)string{
    [self doesNotRecognizeSelector:_cmd];
    return NO;
}

- (NSDictionary *)sonar_requestAttributes{
    [self doesNotRecognizeSelector:_cmd];
    return  nil;
}

#pragma mark -
#pragma mark NSURLConnection delegate methods
#pragma mark -
- (BOOL)connection:(NSURLConnection *)conn 
    canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)space{    
    return YES;
}

- (void)connection:(NSURLConnection *)connection 
    didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
    NSString *method = challenge.protectionSpace.authenticationMethod;

    if([method isEqualToString:NSURLAuthenticationMethodServerTrust]){
        NSURLProtectionSpace *space = challenge.protectionSpace;
        NSURLCredential *credential = nil;
        credential = [NSURLCredential credentialForTrust:space.serverTrust]; 
        
        [challenge.sender useCredential:credential 
                          forAuthenticationChallenge:challenge];    
    }
}

- (void)connection:(NSURLConnection *)connection 
    didReceiveResponse:(NSURLResponse *)response{
    [receivedData_ setLength:0];
}

- (void)connection:(NSURLConnection *)connection 
    didReceiveData:(NSData *)data{
    [receivedData_ appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    NSLog(@"%@",[NSString sonar_stringWithData:receivedData_ 
                                      encoding:NSUTF8StringEncoding]);
    
    UIApplication *sharedApplication = [UIApplication sharedApplication];
    sharedApplication.networkActivityIndicatorVisible = NO;
    
    [self retain];
    
    parserTagStack_ = [[NSMutableArray alloc] init];
    
    dispatch_async(parsingQueue_, ^{
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
        NSXMLParser *parser = [[NSXMLParser alloc] initWithData:receivedData_];
        [parser setDelegate:self];
        [parser parse];
        [parser release]; parser = nil;
        [pool release]; pool = nil;
    });
}

- (void)connection:(NSURLConnection *)connection 
    didFailWithError:(NSError *)error{

    UIApplication *sharedApplication = [UIApplication sharedApplication];
    sharedApplication.networkActivityIndicatorVisible = NO;

}

#pragma mark -
#pragma mark NSXMLParserDelegate methods
#pragma mark -
-(void)parserDidStartDocument:(NSXMLParser *)parser{

}

- (void)parser:(NSXMLParser *)parser 
    didStartElement:(NSString *)elementName 
    namespaceURI:(NSString *)namespaceURI 
    qualifiedName:(NSString *)qualifiedName 
    attributes:(NSDictionary *)attributeDict{
    [self sonar_addParserTagStackString:elementName];
    
    NSString *selectorName = [self sonar_getGetterTagStackString];
    SEL selector = NSSelectorFromString(selectorName);
    if ([self respondsToSelector:selector]){
    	[self performSelector:selector];
    }
    
    [stringBuffer_ release]; stringBuffer_ = nil;
    stringBuffer_ = [[NSMutableString alloc] init];

}

- (void)parser:(NSXMLParser *)parser 
     didEndElement:(NSString *)elementName 
     namespaceURI:(NSString *)namespaceURI 
     qualifiedName:(NSString *)qName{
    
    NSString *selectorName = [self sonar_getSetterTagStackString];
    NSLog(@"%@",selectorName);
    SEL selector = NSSelectorFromString(selectorName);
    if ([self respondsToSelector:selector]){
        [self performSelector:selector withObject:stringBuffer_];
    }
    
    [stringBuffer_ release]; stringBuffer_ = nil;
    
    [self sonar_removeParserTagStackString:elementName];

}

- (void)parser:(NSXMLParser *)parser 
    foundCharacters:(NSString *)string{
    [stringBuffer_  appendString:string];
}

- (void)parserDidEndDocument:(NSXMLParser *)parser{
    dispatch_async(dispatch_get_main_queue(), ^{
        @synchronized(self.delegate){
                [self.delegate serviceHandler:self 
                               didReceiveResponse:responseDataObject_];
        }
    });
    [self release];

}

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{

}

#pragma mark -
#pragma mark Hidden methods
#pragma mark -
- (NSString *)sonar_getSetterTagStackString{
    return [self sonar_getTagStackStringWithPrefix:@"sonar_set" andSufix:@":"];
}

- (NSString *)sonar_getGetterTagStackString{
    return [self sonar_getTagStackStringWithPrefix:@"sonar_get" andSufix:@""];
}

- (NSString *)sonar_getTagStackStringWithPrefix:(NSString *)prefix 
                                     andSufix:(NSString *)sufix{
    NSMutableString *string = [NSMutableString string];
    [string appendString:prefix];
    BOOL first = YES;
    for (NSString *tag in parserTagStack_){
    	if (first){
    		first = NO;
    		[string appendString:[tag sonar_capitalizeFirstLetter]];
    	}else{
    		[string appendString:@"_"];
    		[string appendString:tag];
    	}
    }
    [string appendString:sufix];
    return string;
}

- (void)sonar_addParserTagStackString:(NSString *)string{
    if ([self sonar_validAbstractParserTagStackString:string]){
    	[parserTagStack_ addObject:string];
    }
}

- (void)sonar_removeParserTagStackString:(NSString *)string{
    if ([self sonar_validAbstractParserTagStackString:string]){
    	[parserTagStack_ removeLastObject];
    }
}

- (BOOL)sonar_validAbstractParserTagStackString:(NSString *)string{
    return YES;
}

@end
